// 代码题一
setTimeout(function () {
    var a = 'hello '
    setTimeout(function () {
        var b = 'lagou '
        setTimeout(function () {
            var c = 'I ❤  U'
            console.log(a + b + c)
        }, 10)
    }, 10)
}, 10)

var promise = new Promise((resolve, reject) => {
    setTimeout(function () {
        let a = 'hello '
        resolve(a)
    }, 10)
})
promise.then((value) => {
    return new Promise((resolve, reject) => {
        setTimeout(function () {
            let b = 'lagou '
            resolve(value + b)
        }, 10)
    })
}).then((value) => {
    setTimeout(function () {
        let c = 'I ❤  U'
        console.log(value + c)
    }, 10)
})

// 代码题二
const _ = require('lodash')
const fp = require('lodash/fp')
const cars = [
    {name: 'Ferrari FF', horsepower: 660, dollar_value: 700000, in_stock: true},
    {name: 'Spyker C12 Zagato', horsepower: 650, dollar_value: 648000, in_stock: false},
    {name: 'Jaguar XKR-S', horsepower: 550, dollar_value: 132000, in_stock: false},
    {name: 'Audi R8', horsepower: 525, dollar_value: 114200, in_stock: false},
    {name: 'Aston Martin One-77', horsepower: 750, dollar_value: 1850000, in_stock: true},
    {name: 'Pagani Huayra', horsepower: 700, dollar_value: 1300000, in_stock: false}
]

// 练习一
const isLastInStock = fp.flowRight(fp.prop('in_stock'),fp.last)
console.log(isLastInStock(cars))

// 练习二
const isFirstName = fp.flowRight(fp.prop('name'),fp.first)
console.log(isFirstName(cars))

// 练习三
let _average = function (xs) {
    return fp.reduce(fp.add, 0, xs) / xs.length
}
let averageDollarValue = fp.flowRight(_average,fp.map(fp.prop('dollar_value')))
console.log(averageDollarValue(cars))

// 练习四
let _underscore = fp.replace(/\s+/g, '_')
let sanitizeNames = fp.flowRight(fp.map(_underscore),fp.map(fp.toLower),fp.map(fp.prop('name')))
console.log(sanitizeNames(cars))


// 代码题三

// 练习一
const { Maybe, Container} = require('./support')
let maybe = Maybe.of([5, 6, 1])
let ex1 = (num) => {
    return maybe.map(x => fp.map(fp.add(num), x))
}
console.log(ex1(2))

// 练习二
let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do'])
let ex2 = () => {
    return xs.map((value) => fp.first(value))
}
console.log(ex2())

// 练习三
let safeProp = fp.curry(function (x, o) {
    return Maybe.of(o[x])
})
let user = {id: 2, name: 'Albert'}
let ex3 = (n) => {
    return safeProp('name',n).map(x => fp.first(x))
}
console.log(ex3(user))

// 练习四
let ex4 = function (n) {
    return Maybe.of(n).map(x => parseInt(x))
}
console.log(ex4('2'))




// 代码题四
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
    constructor (executor) {
        try {
            // 创建对象时执行器马上执行
            executor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
    }
    // 初始状态为等待
    status = PENDING
    // 成功之后的值
    value = undefined
    // 失败的原因
    reason = undefined
    // 成功回调
    successCallback = []
    // 失败回调
    failCallback = []
    resolve = (value) => {
        // 如果状态不是等待 阻止程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为成功
        this.status = FULFILLED
        // 保存成功后的值
        this.value = value
        // 判断成功回调是否存在 ，如果存在调用
        //this.successCallback && this.successCallback(value)
        while(this.successCallback.length) this.successCallback.shift()()
    }
    reject = (reason) => {
        // 如果状态不是等待 阻止程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为失败
        this.status = REJECTED
        // 保存失败后的原因
        this.reason = reason
        // 判断失败回调是否存在 ，如果存在调用
        //this.failCallback && this.failCallback(reason)
        while(this.failCallback.length) this.failCallback.shift()()
    }
    then = (successCallback, failCallback) => {
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason}
        // then可以链式调用，所以必须返回一个MyPromise实例
        let promise2 = new MyPromise((resolve, reject) => {
            // 立即执行函数
            // 判断状态
            if (this.status === FULFILLED) {
                // 异步代码可以获取到promise2
                setTimeout(() => {
                    try {
                        // 成功回调的返回值
                        let x = successCallback(this.value)
                        // 判断x的值是普通值还是promise对象
                        // 如果是普通值，直接调用resolve
                        // 如果是promise对象，查看promise对象返回的结果
                        // 再根据promise对象返回的结果，决定调用resolve还是reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        // 失败回调的返回值
                        let x = failCallback(this.reason)
                        // 判断x的值是普通值还是promise对象
                        // 如果是普通值，直接调用resolve
                        // 如果是promise对象，查看promise对象返回的结果
                        // 再根据promise对象返回的结果，决定调用resolve还是reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else {
                // 等待状态
                // 将成功回调失败回调存储下来，等待异步操作完成后有了结果状态再执行
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            // 成功回调的返回值
                            let x = successCallback(this.value)
                            // 判断x的值是普通值还是promise对象
                            // 如果是普通值，直接调用resolve
                            // 如果是promise对象，查看promise对象返回的结果
                            // 再根据promise对象返回的结果，决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            // 失败回调的返回值
                            let x = failCallback(this.reason)
                            // 判断x的值是普通值还是promise对象
                            // 如果是普通值，直接调用resolve
                            // 如果是promise对象，查看promise对象返回的结果
                            // 再根据promise对象返回的结果，决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })
        return promise2
    }
    finally = (callback) => {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
            return MyPromise.resolve(callback()).then(() => {throw reason});
        })
    }
    catch = (failCallback) => {
        return this.then(undefined, failCallback)
    }
    static all (array) {
        let result = [];
        let index = 0
        return new MyPromise((resolve, reject) => {
            function addDate(key, value) {
                result[key] = value;
                index++;
                if (index === array.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    current.then(value => addDate(i, value), reason => reject(reason))
                } else {
                    // 普通值直接放入
                    addDate(i, array[i])
                }
            }
        })
    }
    static resolve(value) {
        if (value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }
}

function resolvePromise (promise2, x, resolve, reject) {
    if (promise2 === x) {
        return reject(new TypeError('Chaing cycle detected for promise'))
    }
    if (x instanceof MyPromise) {
        // promise对象
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}

let myPromise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        reject('失败');
    }, 2000)
    //resolve('成功');
})
// then方法并不会等待异步函数结束才执行，所以需要将then方法中的回调保存起来
let p1 = myPromise.then((value) => {
    console.log(value);
    return p1
})
p1.then(value => {
    console.log(value)
}, reason => {
    console.log(reason)
})

function p2 () {
    return new MyPromise(function (resolve, reject) {
        resolve('p2 resolve')
    })
}
p2().finally(() => {
    console.log('finally')
}).then((value) => {
    console.log('resolve',value)
}, (reason) => {
    console.log('reject',reason)
})